package com.us.usws.support.ext;

import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;

public class GuiceInjectorFactory {

	private static Log log = LogFactory.getFactory().getInstance(GuiceInjectorFactory.class);

	private GuiceInjectorFactory() {
	}

	/*--------- logic methods ----------------*/

	public static Injector getInjector() {
		return InjectorHolder.injector;
	}

	public static Module getModule() {
		return InjectorHolder.module;
	}

	/**
	 * get binded
	 * @param clz
	 * @return
	 */
	public static <T> T getBinded(Class<T> clz) {
		return getInjector().getInstance(clz);
	}

	/*
	 * private class
	 */
	private static class InjectorHolder {
		private static Module module = new SiteGuiceModule();
		private static Injector injector = Guice.createInjector(module);

	}

	public static void dispose() {
		subtractBinding(InjectorHolder.module);
	}

	/**
	 * remove module
	 * @param module
	 * @param toSubtract
	 * @return
	 */
	private static Module subtractBinding(Module module) {
		List<Element> elements = Elements.getElements(module);

		for (Iterator<Element> i = elements.iterator(); i.hasNext();) {
			Element element = i.next();
			boolean remove = element.acceptVisitor(new DefaultElementVisitor<Boolean>() {
				@Override
				public <T> Boolean visit(Binding<T> binding) {
					log.info("Unbiding Key:[" + binding.getKey() + "].");
					return true;
				}

				@Override
				public Boolean visitOther(Element other) {
					return false;
				}
			});
			if (remove) {
				i.remove();
			}
		}

		return Elements.getModule(elements);
	}
}
